#include <glib.h>
#include <SDL.h>
#include "racanhack.h"
#include "task.h"
#include "video.h"
#include "cave.h"
#include "player.h"
#include "floor.h"
#include "los.h"
#include "mapchips.h"

static SDL_Surface *surface_mapchips_light[16];
static SDL_Surface *surface_mapchips_dark[16];
static int interpreter_chip(struct _coord coord);
static gboolean interpreter_los(struct _coord coord);

void mapchips_trans_state(state (*fp)(struct _task *task), struct _mapchips *mapchips)
{
  if (mapchips->task != NULL) {
    mapchips->task->alive = FALSE;
  };
  mapchips->task = task_add(fp, mapchips);
}

static int interpreter_chip(struct _coord coord)
{
  struct _coord c[4];
  gboolean a[4];
  c[0].x = coord.x;
  c[0].y = coord.y;
  c[1].x = coord.x + 1;
  c[1].y = coord.y;
  c[2].x = coord.x;
  c[2].y = coord.y + 1;
  c[3].x = coord.x + 1;
  c[3].y = coord.y + 1;
  if ((c[0].x < 0) ||
      (c[0].y < 0) ||
      (c[3].x >= MAP_W) ||
      (c[3].y >= MAP_H)) return 7;
  a[0] = is_map_pass(c[0]);
  a[1] = is_map_pass(c[1]);
  a[2] = is_map_pass(c[2]);
  a[3] = is_map_pass(c[3]);
  if ( (a[0]) &&  (a[1]) &&
       (a[2]) && !(a[3])) return 0;

  if ( (a[0]) &&  (a[1]) &&
      !(a[2]) && !(a[3])) return 1;

  if ( (a[0]) &&  (a[1]) &&
      !(a[2]) &&  (a[3])) return 2;

  if (!(a[0]) && !(a[1]) &&
      !(a[2]) &&  (a[3])) return 3;

  if (!(a[0]) && !(a[1]) &&
       (a[2]) && !(a[3])) return 4;

  if (!(a[0]) &&  (a[1]) &&
       (a[2]) && !(a[3])) return 5;

  if ( (a[0]) && !(a[1]) &&
       (a[2]) && !(a[3])) return 6;

  if (!(a[0]) && !(a[1]) &&
      !(a[2]) && !(a[3])) return 7;

  if (!(a[0]) &&  (a[1]) &&
      !(a[2]) &&  (a[3])) return 8;

  if (!(a[0]) &&  (a[1]) &&
      !(a[2]) && !(a[3])) return 9;

  if ( (a[0]) && !(a[1]) &&
      !(a[2]) && !(a[3])) return 10;

  if ( (a[0]) && !(a[1]) &&
      !(a[2]) &&  (a[3])) return 11;

  if ( (a[0]) && !(a[1]) &&
       (a[2]) &&  (a[3])) return 12;

  if (!(a[0]) && !(a[1]) &&
       (a[2]) &&  (a[3])) return 13;

  if (!(a[0]) &&  (a[1]) &&
       (a[2]) &&  (a[3])) return 14;

  if ( (a[0]) &&  (a[1]) &&
       (a[2]) &&  (a[3])) return 15;
  g_assert_not_reached();
  return 7;
}

static gboolean interpreter_los(struct _coord coord)
{
  struct _coord c[4];
  c[0].x = coord.x;
  c[0].y = coord.y;
  c[1].x = coord.x + 1;
  c[1].y = coord.y;
  c[2].x = coord.x;
  c[2].y = coord.y + 1;
  c[3].x = coord.x + 1;
  c[3].y = coord.y + 1;
  if ((c[0].x < 0) ||
      (c[0].y < 0) ||
      (c[3].x >= MAP_W) ||
      (c[3].y >= MAP_H)) return FALSE;
  if ((is_los_onsight(c[0])) ||
      (is_los_onsight(c[1])) ||
      (is_los_onsight(c[2])) ||
      (is_los_onsight(c[3]))) {
    return TRUE;
  } else {
    return FALSE;
  };
}

void mapchips_init()
{
  SDL_Surface *s;
  SDL_Rect r;
  s = video_bmp_load("bmp/mapchips_dark.bmp");
  r.w = SPRITE_W;  r.h = SPRITE_H;
  r.x = SPRITE_W * 0;  r.y = SPRITE_H * 0;
  surface_mapchips_dark[0] = video_crop(s,&r);
  r.x = SPRITE_W * 1;  r.y = SPRITE_H * 0;
  surface_mapchips_dark[1] = video_crop(s,&r);
  r.x = SPRITE_W * 2;  r.y = SPRITE_H * 0;
  surface_mapchips_dark[2] = video_crop(s,&r);
  r.x = SPRITE_W * 3;  r.y = SPRITE_H * 0;
  surface_mapchips_dark[3] = video_crop(s,&r);
  r.x = SPRITE_W * 4;  r.y = SPRITE_H * 0;
  surface_mapchips_dark[4] = video_crop(s,&r);
  r.x = SPRITE_W * 5;  r.y = SPRITE_H * 0;
  surface_mapchips_dark[5] = video_crop(s,&r);
  r.x = SPRITE_W * 0;  r.y = SPRITE_H * 1;
  surface_mapchips_dark[6] = video_crop(s,&r);
  r.x = SPRITE_W * 1;  r.y = SPRITE_H * 1;
  surface_mapchips_dark[7] = video_crop(s,&r);
  r.x = SPRITE_W * 2;  r.y = SPRITE_H * 1;
  surface_mapchips_dark[8] = video_crop(s,&r);
  r.x = SPRITE_W * 3;  r.y = SPRITE_H * 1;
  surface_mapchips_dark[9] = video_crop(s,&r);
  r.x = SPRITE_W * 4;  r.y = SPRITE_H * 1;
  surface_mapchips_dark[10] = video_crop(s,&r);
  r.x = SPRITE_W * 5;  r.y = SPRITE_H * 1;
  surface_mapchips_dark[11] = video_crop(s,&r);
  r.x = SPRITE_W * 0;  r.y = SPRITE_H * 2;
  surface_mapchips_dark[12] = video_crop(s,&r);
  r.x = SPRITE_W * 1;  r.y = SPRITE_H * 2;
  surface_mapchips_dark[13] = video_crop(s,&r);
  r.x = SPRITE_W * 2;  r.y = SPRITE_H * 2;
  surface_mapchips_dark[14] = video_crop(s,&r);
  r.x = SPRITE_W * 3;  r.y = SPRITE_H * 2;
  surface_mapchips_dark[15] = video_crop(s,&r);
  SDL_FreeSurface(s);
  s = video_bmp_load("bmp/mapchips_light.bmp");
  r.w = SPRITE_W;  r.h = SPRITE_H;
  r.x = SPRITE_W * 0;  r.y = SPRITE_H * 0;
  surface_mapchips_light[0] = video_crop(s,&r);
  r.x = SPRITE_W * 1;  r.y = SPRITE_H * 0;
  surface_mapchips_light[1] = video_crop(s,&r);
  r.x = SPRITE_W * 2;  r.y = SPRITE_H * 0;
  surface_mapchips_light[2] = video_crop(s,&r);
  r.x = SPRITE_W * 3;  r.y = SPRITE_H * 0;
  surface_mapchips_light[3] = video_crop(s,&r);
  r.x = SPRITE_W * 4;  r.y = SPRITE_H * 0;
  surface_mapchips_light[4] = video_crop(s,&r);
  r.x = SPRITE_W * 5;  r.y = SPRITE_H * 0;
  surface_mapchips_light[5] = video_crop(s,&r);
  r.x = SPRITE_W * 0;  r.y = SPRITE_H * 1;
  surface_mapchips_light[6] = video_crop(s,&r);
  r.x = SPRITE_W * 1;  r.y = SPRITE_H * 1;
  surface_mapchips_light[7] = video_crop(s,&r);
  r.x = SPRITE_W * 2;  r.y = SPRITE_H * 1;
  surface_mapchips_light[8] = video_crop(s,&r);
  r.x = SPRITE_W * 3;  r.y = SPRITE_H * 1;
  surface_mapchips_light[9] = video_crop(s,&r);
  r.x = SPRITE_W * 4;  r.y = SPRITE_H * 1;
  surface_mapchips_light[10] = video_crop(s,&r);
  r.x = SPRITE_W * 5;  r.y = SPRITE_H * 1;
  surface_mapchips_light[11] = video_crop(s,&r);
  r.x = SPRITE_W * 0;  r.y = SPRITE_H * 2;
  surface_mapchips_light[12] = video_crop(s,&r);
  r.x = SPRITE_W * 1;  r.y = SPRITE_H * 2;
  surface_mapchips_light[13] = video_crop(s,&r);
  r.x = SPRITE_W * 2;  r.y = SPRITE_H * 2;
  surface_mapchips_light[14] = video_crop(s,&r);
  r.x = SPRITE_W * 3;  r.y = SPRITE_H * 2;
  surface_mapchips_light[15] = video_crop(s,&r);
  SDL_FreeSurface(s);
}

void mapchips_free()
{
  int i;
  for (i = 0; i < 16; i++) {
    SDL_FreeSurface(surface_mapchips_dark[i]);
    SDL_FreeSurface(surface_mapchips_light[i]);
  };
}

struct _mapchips *mapchips_add()
{
  struct _mapchips *mapchips;
  int i, j;
  mapchips = &Mapchips;
  for (i = 0; i < MAP_W; i++) {
    for (j = 0; j < MAP_H; j++) {
      mapchips->sprite[i][j] = video_sprite_add(Z_ORDER_MAPCHIPS);
      mapchips->sprite[i][j]->x = i * SPRITE_W + (SPRITE_W / 2);
      mapchips->sprite[i][j]->y = j * SPRITE_H + (SPRITE_H / 2);
    };
  };
  mapchips->task = NULL;
  return mapchips;
};

state mapchips_update(struct _task *task)
{
  struct _mapchips *mapchips;
  struct _coord c;
  int chip;
  gboolean los;
  mapchips = (struct _mapchips *)task->pointer[0];
  for (c.x = 0; c.x < MAP_W; c.x++) {
    for (c.y = 0; c.y < MAP_H; c.y++) {
      mapchips->sprite[c.x][c.y]->surface = NULL;
    }
  };
  for (c.x = Player.coord.x - 7; c.x < Player.coord.x + 6; c.x++) {
    for (c.y = Player.coord.y - 6; c.y < Player.coord.y + 5; c.y++) {
      if ((c.x < 0) ||
	  (c.y < 0) ||
	  (c.x >= MAP_W) ||
	  (c.y >= MAP_H)) continue;
      chip = interpreter_chip(c);
      los = interpreter_los(c);
      if (los == TRUE) {
	mapchips->sprite[c.x][c.y]->surface = surface_mapchips_light[chip];
      } else {
	mapchips->sprite[c.x][c.y]->surface = surface_mapchips_dark[chip];
      };
    };
  };
  mapchips->task->alive = FALSE;
  mapchips->task = NULL;
  return;
}
